﻿using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;

namespace tools
{
    class PointLinePlaneTool
    {
        /// <summary>
        /// 点到直线的最短距离（Vector2）
        /// </summary>
        /// <param name="point">直线外点</param>
        /// <param name="A">直线上点A</param>
        /// <param name="B">直线上点B</param>
        /// <returns></returns>
        public static float PointLineMinDistance(Vector2 point, Vector2 A, Vector2 B)
        {
            float length = Mathf.Abs((B.y - A.y) * point.x + (A.x - B.x) * point.y + (B.x - A.x) * A.y + (A.y - B.y) * A.x) / Mathf.Sqrt((B.y - A.y) * (B.y - A.y) + (A.x - B.x) * (A.x - B.x));
            return length;
        }
        /// <summary>
        /// 点到直线的最短距离（Vector3）
        /// </summary>
        /// <param name="point">直线外点</param>
        /// <param name="A">直线上点A</param>
        /// <param name="B">直线上点B</param>
        /// <returns></returns>
        public static float PointLineMinDistance(Vector3 point, Vector3 A, Vector3 B)
        {
            float xDis = B.x - A.x;
            float yDis = B.y - A.y;
            float zDis = B.z - A.z;
            float dx = point.x - A.x;
            float dy = point.y - A.y;
            float dz = point.z - A.z;
            float d = xDis * xDis + yDis * yDis + zDis * zDis;
            float t = xDis * dx + yDis * dy + zDis * dz;//向量点积

            if (d > 0)
            {
                t /= d;
            }
            if (t < 0)
            {
                t = 0;
            }
            else if (t > 1)
            {
                t = 1;
            }
            dx = A.x + t * xDis - point.x;
            dy = A.y + t * yDis - point.y;
            dz = A.z + t * zDis - point.z;
            return Mathf.Sqrt(dx * dx + dy * dy + dz * dz);
        }
        /// <summary>
        /// 判断点是否在多边形内部
        /// </summary>
        /// <param name="p">点</param>
        /// <param name="vertexs">组成多边形的点</param>
        /// <returns></returns>
        public static bool IsPointInPolygon(Vector2 p, List<Vector2> vertexs)
        {
            int crossNum = 0;
            int vertexCount = vertexs.Count;

            for (int i = 0; i < vertexCount; i++)
            {
                Vector2 v1 = vertexs[i];
                Vector2 v2 = vertexs[(i + 1) % vertexCount];

                if (((v1.y <= p.y) && (v2.y > p.y))
                    || ((v1.y > p.y) && (v2.y <= p.y)))
                {
                    if (p.x < v1.x + (p.y - v1.y) / (v2.y - v1.y) * (v2.x - v1.x))
                    {
                        crossNum += 1;
                    }
                }
            }
            if (crossNum % 2 == 0)
            {
                return false;
            }
            else
            {
                return true;
            }
        }
        /// <summary>
        /// 计算AB与CD两条线段的交点.
        /// </summary>
        /// <param name="a">A点</param>
        /// <param name="b">B点</param>
        /// <param name="c">C点</param>
        /// <param name="d">D点</param>
        /// <param name="intersectPos">AB与CD的交点</param>
        /// <returns>是否相交 true:相交 false:未相交</returns>
        public static bool LineIntersectPoint(Vector3 a, Vector3 b, Vector3 c, Vector3 d, out Vector3 intersectPos)
        {
            intersectPos = Vector3.zero;

            Vector3 ab = b - a;
            Vector3 ca = a - c;
            Vector3 cd = d - c;

            Vector3 v1 = Vector3.Cross(ca, cd);

            if (Mathf.Abs(Vector3.Dot(v1, ab)) > 1e-6)
            {
                // 不共面
                return false;
            }

            if (Vector3.Cross(ab, cd).sqrMagnitude <= 1e-6)
            {
                // 平行
                return false;
            }

            Vector3 ad = d - a;
            Vector3 cb = b - c;
            // 快速排斥
            if (Mathf.Min(a.x, b.x) > Mathf.Max(c.x, d.x) || Mathf.Max(a.x, b.x) < Mathf.Min(c.x, d.x)
               || Mathf.Min(a.y, b.y) > Mathf.Max(c.y, d.y) || Mathf.Max(a.y, b.y) < Mathf.Min(c.y, d.y)
               || Mathf.Min(a.z, b.z) > Mathf.Max(c.z, d.z) || Mathf.Max(a.z, b.z) < Mathf.Min(c.z, d.z)
            )
                return false;

            // 跨立试验
            if (Vector3.Dot(Vector3.Cross(-ca, ab), Vector3.Cross(ab, ad)) > 0
                && Vector3.Dot(Vector3.Cross(ca, cd), Vector3.Cross(cd, cb)) > 0)
            {
                Vector3 v2 = Vector3.Cross(cd, ab);
                float ratio = Vector3.Dot(v1, v2) / v2.sqrMagnitude;
                intersectPos = a + ab * ratio;
                return true;
            }

            return false;
        }
        /// <summary>
        /// 计算直线与平面的交点
        /// </summary>
        /// <param name="point">直线上某一点</param>
        /// <param name="direct">直线的方向</param>
        /// <param name="planeNormal">垂直于平面的的向量</param>
        /// <param name="planePoint">平面上的任意一点</param>
        /// <returns></returns>
        public static Vector3 GetIntersectWithLineAndPlane(Vector3 point, Vector3 direct, Vector3 planeNormal, Vector3 planePoint)
        {
            float d = Vector3.Dot(planePoint - point, planeNormal) / Vector3.Dot(direct.normalized, planeNormal);
            //print(d);
            return d * direct.normalized + point;
        }
    }
    
}
